/**
 * FileName: LoginServiceImpl
 * Author: TangZaoBang
 * Date: 2023/06/05 13:09
 * Description: 角色服务
 * <p>
 * History:
 * <author> TangZaoBang
 * <time> 2023/06/05 13:09
 * <version> 1.0.0
 * <desc> 版本描述
 */
package com.sd365.permission.centre.service.impl;

import cn.hutool.core.lang.Assert;
import com.github.pagehelper.Page;
import com.sd365.common.core.annotation.mybatis.Pagination;
import com.sd365.common.core.annotation.stuffer.CommonFieldStuffer;
import com.sd365.common.core.annotation.stuffer.IdGenerator;
import com.sd365.common.core.annotation.stuffer.MethodTypeEnum;
import com.sd365.common.core.common.api.CommonPage;
import com.sd365.common.core.common.constant.EntityConsts;
import com.sd365.common.core.common.exception.BusinessException;
import com.sd365.common.core.common.exception.code.BizErrorCode;
import com.sd365.common.core.common.pojo.entity.TenantBaseEntity;
import com.sd365.common.core.common.service.AbstractBusinessService;
import com.sd365.common.util.BeanException;
import com.sd365.common.util.BeanUtil;

import com.sd365.permission.centre.dao.mapper.*;
import com.sd365.permission.centre.entity.*;
import com.sd365.permission.centre.pojo.dto.*;
import com.sd365.permission.centre.pojo.query.CompanyQuery;
import com.sd365.permission.centre.pojo.query.RoleQuery;
import com.sd365.permission.centre.pojo.query.UserQuery;
import com.sd365.permission.centre.pojo.vo.RoleCompanyVO;
import com.sd365.permission.centre.service.RoleService;
import com.sd365.permission.centre.service.cache.IRoleCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import tk.mybatis.mapper.entity.Example;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 *
 * @Description able.zhan 2022-09-30
 * @Author Administrator
 * @Date 2022-9-30  16:24

 */
/**
 * 重构了 人员分配，如果该类触发校验异常或者业务异常将由统一异常处理
 *  * 包含注意方法：1 初始化角色和缓存关系用于网关鉴权提速 2 为角色分配权限 3 为角色分配用户
 *  1 优化了插入效率改为批量更新  2  角色重新分配的时候优化缓存
 * @Class RoleServiceImpl
 * @author TangZaoBang
 * @date 2023/06/15 12:15
 * @version 1.0.0
 */
@Service
@Slf4j
public class RoleServiceImpl extends AbstractBusinessService implements RoleService {
    private static final String COLUMN_ROLE_ID = "roleId";
    /**
     * 角色缓存操作类
     */
    @Autowired
    private IRoleCache roleCache;

    /**
     *  角色mapper
     */
    @Autowired
    private RoleMapper roleMapper;

    /**
     *  角色资源mapper 对应basic_role_resource表
     */
    @Autowired
    private RoleResourceMapper roleResourceMapper;

    /**
     *  角色所处公司查询，一个角色可以属于多个公司
     */
    @Autowired
    private RoleCompanyMapper roleCompanyMapper;
    /**
     * 用户角色查询 对应 basic_user_role表
     */
    @Autowired
    private UserRoleMapper userRoleMapper;

    /**
     *  用户mapper
     */
    @Autowired
    private UserMapper userMapper;

    /**
     * id 生成器
     */
    @Autowired
    private IdGenerator idGenerator;

    /**
     * 资源mapper
     */
    @Autowired
    private ResourceMapper resourceMapper;
    /**
     * 将初始大小设置为 1000
     */

    private static final int INITIAL_CAPACITY = 1000;

    /**
     * 职位mapper
     */
    @Autowired
    private PositionMapper positionMapper;

    /**
     * 公司mapper
     */
    @Autowired
    private CompanyMapper companyMapper;

    /**
     * 部门mapper
     */
    @Autowired
    private DepartmentMapper departmentMapper;
    /**
     * stringRedisTemplate 用来存储锁
     * @author TangZaoBang
     * @date 2023/06/14 12:13
     */
    @javax.annotation.Resource(name = "MyLockRedisTemplate")
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 缓存角色和资源的关系
     * @author TangZaoBang
     * @date 2023/06/15 00:18
     * @param role
     * @return java.lang.Boolean
     */
    @Override
    public Boolean loadRoleResource2Cache(@NotNull Role role) {
        List<Role> roles = roleMapper.commonQuery(role);
        if (CollectionUtils.isEmpty(roles)) {
            throw new BusinessException(BizErrorCode.DATA_SEARCH_NOT_FOUND, "没有找到对应的角色");
        }
        // 提取角色ID列表
        List<Long> roleIds = roles.stream().map(Role::getId).collect(Collectors.toList());
        // 批量查询角色资源列表
        Example example = new Example(RoleResource.class);
        example.createCriteria().andIn(COLUMN_ROLE_ID, roleIds);
        List<RoleResource> roleResourceList = roleResourceMapper.selectByExample(example);

        // 构建角色ID和资源列表的映射关系
        Map<Long, List<RoleResource>> roleResourceMap = new HashMap<>(INITIAL_CAPACITY);
        for (RoleResource roleResource : roleResourceList) {
            /**
             * 对于每个角色资源对象，检查其角色ID对应的键是否存在。
             * 如果存在，则获取对应的值，并将当前角色资源对象添加到值（资源列表）中。
             * 如果不存在，则创建一个新的空列表，并将当前角色资源对象添加到该列表中，然后将列表与角色ID进行映射，添加到映射关系中。
             */
            roleResourceMap.computeIfAbsent(roleResource.getRoleId(), k -> new ArrayList<>()).add(roleResource);
        }
        // 遍历角色列表，缓存资源列表
        for (Role role1 : roles) {
            List<RoleResource> resources = roleResourceMap.get(role1.getId());
            if (CollectionUtils.isEmpty(resources)) {
                continue;
            }
            /**
             * 每个角色 定义为一个 hashmap对象放在 redis ， hash对象在内存中的key为
             * Global.HASH_ROLE_ID_KEY+role1.getId(),  hashmap 的key为 RoleResource的id
             * value为 RoleResource对象
             */
            roleCache.cacheRoleResource(role1, resources);
        }

        return Boolean.TRUE;
    }


    /**
     * 批量插入，插入前先删除原来的角色和资源的关系
     * @param: 前端选择的角色资源列表
     * @return: 成功ture 失败 false
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean assignResource(@NotNull @Valid RoleResourceDTO roleResourceDTO) {
        // 给多个角色分配多个资源 参数去重复
        List<Long> roleIds = new ArrayList<>(new HashSet<>(roleResourceDTO.getRoleIds()));
        List<Long> resourceIds = new ArrayList<>(new HashSet<>(roleResourceDTO.getResourceIds()));
        // 删除原来的角色资源
        boolean removeResult = false;
        synchronized (this) {
            removeResult = removeRolesResources(roleIds);
        }
        if (!removeResult) {
            throw new BusinessException("401", "更新角色资源关系失败，可能存在并发访问问题。");
        }
        // 批量插入新的角色资源关系
        boolean insertResult = batchInsertRolesResources(roleIds, resourceIds);
        if (!insertResult) {
            // 因为已经删除了原有的角色资源关系，如果插入失败，则抛出异常进行回滚处理
            throw new BusinessException("401", "插入角色资源关系失败，进行回滚操作。");
        }
        // 开始重置缓存
        updateRoleCache(roleIds);
        return true;
    }

    /**
     * 更新角色资源
     * @author TangZaoBang
     * @date 2023/06/14 13:10
     * @param roleIds
     * @return void
     */
    @CommonFieldStuffer(methodType = MethodTypeEnum.UPDATE)
    private void updateRoleCache(List<Long> roleIds) {
        List<Role> roleList = roleIds.stream()
                .map(id -> {
                    Role role = new Role();
                    role.setId(id);
                    return role;
                })
                .collect(Collectors.toList());

        // 使用Redis分布式锁来保证只有一个线程可以更新缓存
        String lockKey = "roleCacheUpdateLock";
        String lockValue = UUID.randomUUID().toString();
        boolean lockAcquired = false;
        try {
            // 尝试获取锁，设置一个较短的超时时间，防止死锁
            lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 10, TimeUnit.SECONDS);
            if (lockAcquired) {
                // 更新缓存
                roleCache.cachedMultiRolesResrouces(roleList);
            } else {
                throw new BusinessException("401", "无法获取缓存更新锁，可能存在并发访问问题。");
            }
        } finally {
            // 释放锁
            if (lockAcquired) {
                redisTemplate.delete(lockKey);
            }
        }
    }

    /**
     * 将角色分配给用户
     * @author TangZaoBang
     * @date 2023/06/14 14:24
     * @param userRoleDTO 要更改的信息
     * @return java.lang.Boolean
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean assignUser(@NotNull @Valid UserRoleDTO userRoleDTO) {
        List<Long> roleIds = new ArrayList<>(new HashSet<>(userRoleDTO.getRoleIds()));
        List<Long> userIds = new ArrayList<>(new HashSet<>(userRoleDTO.getUserIds()));
        //删除原来用户所对应的角色
        boolean removeResult = false;
        synchronized (this) {
            removeResult = deleteExistingUserRoles(userIds);
        }
        if (!removeResult) {
            throw new BusinessException("401", "更新角色资源关系失败，可能存在并发访问问题。");
        }
        // 插入角色所包含的新用户
        int insertRows = insertNewUserRoles(roleIds, userIds);
        return insertRows > 0;
    }

    /**
     * deleteExistingUserRoles 删除原来用户所对应的角色
     * @author TangZaoBang
     * @date 2023/06/14 14:31
     * @param userIds  勾选的userId
     * @return java.lang.Boolean
     */
    private Boolean deleteExistingUserRoles(List<Long> userIds) {
        if (userIds.isEmpty()) {
            return true;
        }
        Example example = new Example(UserRole.class);
        example.createCriteria().andIn("userId", userIds);
        if (userRoleMapper.selectByExample(example).isEmpty()){
            return true;
        }
        return userRoleMapper.deleteByExample(example) > 0;
    }

    /**
     * 插入新的角色
     * @author TangZaoBang
     * @date 2023/06/14 14:32
     * @param roleIds 要插入的角色
     * @param userIds 对应的用户
     * @return int
     */
    @CommonFieldStuffer(methodType = MethodTypeEnum.ADD)
    private int insertNewUserRoles(List<Long> roleIds, List<Long> userIds) {
        int insertRows = 0;
        for (Long roleId : roleIds) {
            for (Long userId : userIds) {
                UserRole userRole = createNewUserRole(roleId, userId);
                insertRows += userRoleMapper.insert(userRole);
            }
        }
        return insertRows;
    }

    private UserRole createNewUserRole(Long roleId, Long userId) {
        UserRole userRole = new UserRole();
        userRole.setRoleId(roleId);
        userRole.setId(idGenerator.snowflakeId());
        userRole.setUserId(userId);
        userRole.setStatus((byte) EntityConsts.INITIAL_STATUS);
        userRole.setVersion(EntityConsts.INITIAL_VERSION);
        // 公用字段补充未来直接myabtis插件填写
        super.baseDataStuff4Add(userRole);
        super.baseDataStuffCommonPros(userRole);
        return userRole;
    }

    @Override
    public List<Node> queryResourceByRoleId(long roleId) {

        return roleResourceMapper.queryResourceByRoleId(roleId);
    }

    @Override
    public List<Node> selectCompany() {
        return roleMapper.selectCompany();
    }

    @Override
    public boolean haveRole(@Valid RoleDTO roleDTO) {
        Role role = BeanUtil.copy(roleDTO, Role.class);
        return roleMapper.haveRole(role) > 0;
    }

    /**
     * 要求code 不能重复 ，有参数校验
     * @author TangZaoBang
     * @date 2023/06/07 19:03
     * @param roleDTO 传入的角色dto
     * @return java.lang.Boolean
     */
    @Override
    @CommonFieldStuffer(methodType = MethodTypeEnum.ADD)
    public Boolean add(@Valid @NotNull RoleDTO roleDTO) {
        Role role = BeanUtil.copy(roleDTO, Role.class);
        if (roleMapper.selectRoleByCode(role.getCode()) == 0) {
            role.setId(idGenerator.snowflakeId());
            return roleMapper.insert(role) > 0;
        } else {
            throw new BusinessException("401", "code已经存在，请换一个");
        }
    }

    /**
     * 删除角色，注意如果角色被使用不可以删除,同时要删除角色对应资源
     * 删除缓存之前判断是否存在
     * @author TangZaoBang
     * @date 2023/06/07 21:03
     * @param id id
     * @param version  版本
     * @return java.lang.Boolean
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean removeByIdAndVersion(@NotNull Long id, @NotNull Long version) {
        // 删除 RoleResource 表中符合条件的记录
        Example exampleRoleResource = new Example(RoleResource.class);
        exampleRoleResource.createCriteria().andEqualTo(COLUMN_ROLE_ID, id);
        roleResourceMapper.deleteByExample(exampleRoleResource);
        // 删除 UserRole 表中符合条件的记录
        Example exampleUserRole = new Example(UserRole.class);
        exampleUserRole.createCriteria().andEqualTo(COLUMN_ROLE_ID, id);
        userRoleMapper.deleteByExample(exampleUserRole);
        //删除 UserRoleCompany 表中符合条件的记录
        Example companyExample = new Example(UserRole.class);
        companyExample.createCriteria().andEqualTo(COLUMN_ROLE_ID, id);
        roleCompanyMapper.deleteByExample(companyExample);
        // 删除 Role 表中符合条件的记录，并将删除结果赋给 result
        Example exampleRole = new Example(Role.class);
        exampleRole.createCriteria().andEqualTo("id", id).andEqualTo("version", version);
        boolean result = roleMapper.deleteByExample(exampleRole) > 0;
        // 如果成功删除了角色记录，则移除缓存中的角色和资源管理
        if (result) {
            roleCache.removeCacheRoleResources(id);
        }
        Assert.isTrue(result, String.format("删除的记录id %d 没有匹配到版本", id));
        return result;
    }


    /**
     * 修改角色
     * @author TangZaoBang
     * @date 2023/06/13 14:26
     * @param roleDTO 修改角色的内容
     * @return com.sd365.permission.centre.pojo.dto.RoleDTO
     */
    @Override
    @CommonFieldStuffer(methodType = MethodTypeEnum.UPDATE)
    public RoleDTO modify(@NotNull RoleDTO roleDTO) {
        Role role = roleMapper.selectById(roleDTO.getId());
        role.setUpdatedTime(new Date());
        role = BeanUtil.copy(roleDTO, Role.class);
        BeanUtil.copy(roleDTO, role);
        if (roleMapper.updateByPrimaryKey(role) > 0) {
            RoleDTO roleDtoCache = BeanUtil.copy(role, RoleDTO.class);
            BeanUtil.copy(role.getCompany(), roleDtoCache.getCompanyDTO(), CompanyDTO.class);
            BeanUtil.copy(role.getOrganization(), roleDtoCache.getOrganizationDTO(), OrganizationDTO.class);
            BeanUtil.copy(role.getTenant(), roleDtoCache.getTenantDTO(), TenantDTO.class);
            return roleDtoCache;
        }
        return new RoleDTO();

    }

    /**
     * 查询角色 依据 UI的查询区条件
     * @author TangZaoBang
     * @date 2023/06/13 14:29
     * @param roleQuery 查询条件
     * @return com.sd365.common.core.common.api.CommonPage<com.sd365.permission.centre.pojo.dto.RoleDTO>
     */
    @Pagination
    @CommonFieldStuffer(methodType = MethodTypeEnum.QUERY)
    @Override
    public CommonPage<RoleDTO> commonQuery(@NotNull RoleQuery roleQuery) {

        Role role = new Role();
        BeanUtil.copy(roleQuery, role);

        // 因为分页插入应用的原因 这里返回的类型为 Page ，class Page extends ArrayList
        Page<Role> roles = (Page<Role>) roleMapper.commonQuery(role);
        //对象转化 po list to dto list
        List<RoleDTO> roleDTOList = BeanUtil.copyList(roles, RoleDTO.class, (o, o1) -> {
            // 调用 BeanUtil.copyProperties
            if (o == null || o1 == null) {
                throw new BeanException("拷贝对象不可以为空", new Exception("copyList 拷贝回调错误"));
            }
            Role roleSource = (Role) o;
            RoleDTO roleDTO = (RoleDTO) o1;
            BeanUtil.copy(roleSource.getCompany(), roleDTO.getCompanyDTO(), CompanyDTO.class);
            BeanUtil.copy(roleSource.getOrganization(), roleDTO.getOrganizationDTO(), OrganizationDTO.class);
            BeanUtil.copy(roleSource.getTenant(), roleDTO.getTenantDTO(), TenantDTO.class);
        });

        return cast2CommonPage(roles, roleDTOList);
    }


    /**
     * 根据id找到对应的角色
     * @author TangZaoBang
     * @date 2023/06/08 22:06
     * @param roleId  角色id
     * @return com.sd365.permission.centre.pojo.dto.RoleDTO
     */
    @Override
    public RoleDTO queryById(@NotNull Long roleId) {
        RoleDTO roleDTO = new RoleDTO();
        Role role = roleMapper.selectById(roleId);
        if (role != null) {
            roleDTO = BeanUtil.copy(role, RoleDTO.class);
            BeanUtil.copy(role.getCompany(), roleDTO.getCompanyDTO(), CompanyDTO.class);
            BeanUtil.copy(role.getOrganization(), roleDTO.getOrganizationDTO(), OrganizationDTO.class);
            BeanUtil.copy(role.getTenant(), roleDTO.getTenantDTO(), TenantDTO.class);
        }
        return roleDTO;

    }

    @Override
    public RoleDTO copy(@NotNull Long id) {
        Role role = roleMapper.selectByPrimaryKey(id);
        return role != null ? BeanUtil.copy(role, RoleDTO.class) : new RoleDTO();
    }

    /**
     * 批量删除角色 和对应的资源
     * @author TangZaoBang
     * @date 2023/06/09 12:38
     * @param idVersions
     * @return java.lang.Boolean
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean batchRemove(@NotEmpty @Valid IdVersion[] idVersions) {
        for (IdVersion idVersion : idVersions) {
            removeByIdAndVersion(idVersion.getId(), idVersion.getVersion());
        }
        return true;
    }

    /**
     * commonQueryUser
     * @author TangZaoBang
     * @date 2023/06/14 17:15
     * @param userQuery
     * @return com.sd365.common.core.common.api.CommonPage<com.sd365.permission.centre.pojo.dto.UserDTO>
     */
    @Pagination
    @Override
    public CommonPage<UserDTO> commonQueryUser(@NotNull UserQuery userQuery) {
        Example example = new Example(User.class);
        example.setOrderByClause("updated_time DESC");
        Example.Criteria criteria = example.createCriteria();

        if (userQuery.getCode() != null) {
            criteria.orLike("code", "%" + userQuery.getCode() + "%");
        } else {
            criteria.orLike("code", userQuery.getCode());
        }

        if (userQuery.getName() != null) {
            criteria.orLike("name", "%" + userQuery.getName() + "%");
        } else {
            criteria.orLike("name", userQuery.getName());
        }

        Page<User> users = (Page) userMapper.selectByExample(example);

        List<UserDTO> userDtoList = BeanUtil.copyList(users, UserDTO.class);

        if (!CollectionUtils.isEmpty(userDtoList)) {
            Map<Long, CompanyDTO> companyVoMap = buildCompanyMap();
            Map<Long, PositionDTO> positionHashMap = buildPositionMap();
            Map<Long, DepartmentDTO> departmentDtoMap = buildDepartmentMap();
            for (UserDTO userDTO : userDtoList) {
                setCompany(userDTO, companyVoMap);
                setPosition(userDTO, positionHashMap);
                setDepartment(userDTO, departmentDtoMap);
            }
        }

        return cast2CommonPage(users, userDtoList);
    }

    private Map<Long, CompanyDTO> buildCompanyMap() {
        List<Company> companies = companyMapper.commonQuery(new CompanyQuery());
        Map<Long, CompanyDTO> companyVoMap = new HashMap<>(INITIAL_CAPACITY);
        for (Company company : companies) {
            companyVoMap.put(company.getId(), BeanUtil.copy(company, CompanyDTO.class));
        }
        return companyVoMap;
    }

    private Map<Long, PositionDTO> buildPositionMap() {
        List<Position> positions = positionMapper.selectAll();
        Map<Long, PositionDTO> positionHashMap = new HashMap<>(INITIAL_CAPACITY);
        for (Position position : positions) {
            positionHashMap.put(position.getId(), BeanUtil.copy(position, PositionDTO.class));
        }
        return positionHashMap;
    }

    private Map<Long, DepartmentDTO> buildDepartmentMap() {
        List<Department> departments = departmentMapper.selectAll();
        Map<Long, DepartmentDTO> departmentDtoMap = new HashMap<>(INITIAL_CAPACITY);
        for (Department department : departments) {
            departmentDtoMap.put(department.getId(), BeanUtil.copy(department, DepartmentDTO.class));
        }
        return departmentDtoMap;
    }

    private void setCompany(UserDTO userDTO, Map<Long, CompanyDTO> companyVoMap) {
        if (!ObjectUtils.isEmpty(userDTO.getCompanyId())) {
            userDTO.setCompany(companyVoMap.get(userDTO.getCompanyId()));
        }
    }

    private void setPosition(UserDTO userDTO, Map<Long, PositionDTO> positionHashMap) {
        if (!ObjectUtils.isEmpty(userDTO.getPositionId())) {
            userDTO.setPosition(positionHashMap.get(userDTO.getPositionId()));
        }
    }

    private void setDepartment(UserDTO userDTO, Map<Long, DepartmentDTO> departmentDtoMap) {
        if (!ObjectUtils.isEmpty(userDTO.getDepartmentId())) {
            userDTO.setDepartment(departmentDtoMap.get(userDTO.getDepartmentId()));
        }
    }

    @Override
    public RoleDTO queryUserResource(Long id) {
        /**
         * 取得用户所有的角色id
         */
        Role role = roleMapper.selectByPrimaryKey(id);
        Example example = new Example(RoleResource.class);
        example.selectProperties("resourceId");
        example.createCriteria().andEqualTo(COLUMN_ROLE_ID, id);
        List<RoleResource> roleResources = roleResourceMapper.selectByExample(example);
        Set<Long> idSet = new HashSet<>();
        for (RoleResource roleResource : roleResources) {
            idSet.add(roleResource.getResourceId());
        }
        // 根据所有的角色id取得所有的资源
        if (!idSet.isEmpty()) {
            Example re = new Example(Resource.class);
            re.createCriteria().andIn("id", idSet);
            // 重复的要去除
            List<Resource> resources = resourceMapper.selectByExample(re);
            resources = resources.stream().distinct().collect(Collectors.toList());
            List<ResourceDTO> resourceDtoList = BeanUtil.copyList(resources, ResourceDTO.class);
            RoleDTO copy = BeanUtil.copy(role, RoleDTO.class);
            copy.setResourceDTOS(resourceDtoList);
            return copy;
        } else {
            return new RoleDTO();
        }
    }

    @Override
    public RoleCompanyVO queryRoleCompanyById(@NotNull Long id) {
        Example example = new Example(RoleCompany.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(COLUMN_ROLE_ID, id);
        // 获取对应角色id的 角色-授权公司 列表
        List<RoleCompany> roleCompanyList = roleCompanyMapper.selectByExample(example);
        List<Long> authCompanyIds = roleCompanyList.stream().map(RoleCompany::getAuthCompanyId)
                .collect(Collectors.toList());
        // 角色所属于的公司
        RoleCompanyVO roleCompanyVO = new RoleCompanyVO();
        roleCompanyVO.setRoleId(id);
        roleCompanyVO.setAuthCompanyIds(authCompanyIds);
        return roleCompanyVO;
    }

    @Override
    public Boolean modifyRoleCompany(@NotNull @Valid RoleCompanyDTO roleCompanyDTO) {
        List<Long> roleIds = roleCompanyDTO.getRoleIds();
        for (Long roleId : roleIds) {
            Example selectExample = new Example(RoleCompany.class);
            Example.Criteria selectCriteria = selectExample.createCriteria();
            selectCriteria.andEqualTo(COLUMN_ROLE_ID, roleId);
            // 获取数据库 原有的(old) 对应角色id的 角色-授权公司 id列表
            List<RoleCompany> roleCompanyList = roleCompanyMapper.selectByExample(selectExample);
            List<Long> oldAuthCompanyIdList = roleCompanyList.stream()
                    .map(RoleCompany::getAuthCompanyId).collect(Collectors.toList());
            // 获取前端传来的 最新的(new) 角色id的 角色-授权公司 id列表
            List<Long> newAuthCompanyIdList = roleCompanyDTO.getAuthCompanyIds();

            // 旧的id列表去掉已经在新的id列表的那部分（去掉交集）是准备要删除的
            List<Long> toDelete = oldAuthCompanyIdList.stream()
                    .filter(id -> !newAuthCompanyIdList.contains(id)).collect(Collectors.toList());
            // 新的id列表去掉在旧的id列表的那部分（去掉交集）是准备要添加的
            List<Long> toInsert = newAuthCompanyIdList.stream()
                    .filter(id -> !oldAuthCompanyIdList.contains(id)).collect(Collectors.toList());

            if (!toDelete.isEmpty()) {
                Example deleteExample = new Example(RoleCompany.class);
                Example.Criteria deleteCriteria = deleteExample.createCriteria();
                deleteCriteria.andEqualTo(COLUMN_ROLE_ID, roleId).andIn("authCompanyId", toDelete);
                roleCompanyMapper.deleteByExample(deleteExample);
            }

            List<RoleCompany> insertRoleCompanyList = new ArrayList<>();
            toInsert.forEach(authCompanyId -> {
                RoleCompany roleCompany = new RoleCompany();
                roleCompany.setRoleId(roleId);
                roleCompany.setAuthCompanyId(authCompanyId);
                initEntity(roleCompany);
                insertRoleCompanyList.add(roleCompany);
            });
            if (!insertRoleCompanyList.isEmpty()) {
                roleCompanyMapper.insertList(insertRoleCompanyList);
            }
        }
        return true;
    }


    /**
     * 初始化对象公共属性
     * @param entity
     */
    private void initEntity(TenantBaseEntity entity) {
        entity.setId(idGenerator.snowflakeId());
        baseDataStuff4Add(entity);
        baseDataStuffCommonPros(entity);
        entity.setStatus(EntityConsts.INITIAL_STATUS);
        entity.setVersion(EntityConsts.INITIAL_VERSION);
    }


    /**
     *  删除角色的所有的资源
     * @param roleIds  角色id列表
     * @return true成功 false失败  如果成功外部调用删除缓存
     */
    private boolean removeRolesResources(List<Long> roleIds) {
        // 进行角色分配 采用先删除后插入的策略
        Example example = new Example(RoleResource.class);
        example.createCriteria().andIn(COLUMN_ROLE_ID, roleIds);
        if (roleResourceMapper.selectByExample(example).isEmpty()){
            return true;
        }
        return roleResourceMapper.deleteByExample(example) > 0;
    }

    /**
     *  批量插入角色资源关系
     * @param roleIds  角色列表
     * @param resources 角色所拥有的资源的列表
     * @return true成功 false失败
     */
    @CommonFieldStuffer(methodType = MethodTypeEnum.ADD)
    private boolean batchInsertRolesResources(List<Long> roleIds, List<Long> resources) {
        Set<RoleResource> roleResourceSet = new HashSet<>();
        // 构建插入数据 且去重复 依据 角色id，资源id，租户
        for (Long roleId : roleIds) {
            resources.stream().forEach(resourceId -> {
                RoleResource roleResource = new RoleResource();
                roleResource.setRoleId(roleId);
                roleResource.setId(idGenerator.snowflakeId());
                roleResource.setResourceId(resourceId);
                baseDataStuff4Add(roleResource);
                roleResource.setStatus(EntityConsts.INITIAL_STATUS);
                roleResource.setVersion(EntityConsts.INITIAL_VERSION);
                roleResourceSet.add(roleResource);
            });
        }
        List<RoleResource> roleResourceList = CollectionUtils.arrayToList(roleResourceSet.toArray());
        // 批量插入避免数据库插入堵塞
        int times = roleResourceList.size() / 100;
        int total = 0;
        for (int i = 0; i < times; i++) {
            total += roleResourceMapper.batchInsert(roleResourceList.subList(i * 100, (i + 1) * 100));
        }
        if (roleResourceList.size() > total) {
            total += roleResourceMapper.batchInsert(roleResourceList.subList(total, roleResourceList.size()));
        }
        return roleResourceList.size() == total;
    }
}